package org.dromara.workflow.flowable.config;

import cn.hutool.core.collection.CollUtil;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.workflow.common.enums.TaskStatusEnum;
import org.dromara.workflow.flowable.handler.TaskTimeoutJobHandler;
import org.dromara.workflow.utils.QueryUtils;
import org.flowable.bpmn.model.BoundaryEvent;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.common.engine.api.delegate.event.*;
import org.flowable.common.engine.impl.cfg.TransactionState;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.task.Comment;
import org.flowable.job.service.TimerJobService;
import org.flowable.job.service.impl.persistence.entity.JobEntity;
import org.flowable.job.service.impl.persistence.entity.TimerJobEntity;
import org.flowable.task.api.Task;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;



/**
 * @Author 刘武贵
 * @Date 2024/8/15 22:00
 * @Description 功能描述：引擎调度监听
 */
/**
 * 全局流程监听器类，实现FlowableEventListener接口
 * 该类作为流程引擎的全局监听器，用于处理流程引擎中发生的各种事件
 */
@Component
public class GlobalFlowableListener implements FlowableEventListener {

    /**
     * 使用TaskService来处理任务相关的操作，@Autowired用于自动装配bean，@Lazy表示延迟加载
     */
    @Autowired
    @Lazy
    private TaskService taskService;

    /**
     * 使用RuntimeService来处理运行时相关的操作，@Autowired用于自动装配bean，@Lazy表示延迟加载
     */
    @Autowired
    @Lazy
    private RuntimeService runtimeService;

    /**
     * 使用RepositoryService来处理仓库相关的操作，@Autowired用于自动装配bean，@Lazy表示延迟加载
     */
    @Autowired
    @Lazy
    private RepositoryService repositoryService;

    /**
     * 表示是否激活Flowable的异步执行器
     */
    @Value("${flowable.async-executor-activate}")
    private boolean asyncExecutorActivate;

    /**
     * 处理Flowable事件的回调方法
     *
     * @param flowableEvent Flowable事件对象，用于处理不同的事件类型
     */
    @Override
    public void onEvent(FlowableEvent flowableEvent) {
        // 检查是否为Flowable引擎事件
        if (flowableEvent instanceof FlowableEngineEvent flowableEngineEvent) {
            // 获取事件类型
            FlowableEngineEventType engineEventType = (FlowableEngineEventType) flowableEvent.getType();
            // 根据事件类型执行不同操作
            switch (engineEventType) {
                // 任务执行成功事件
                case JOB_EXECUTION_SUCCESS -> jobExecutionSuccess((FlowableEngineEntityEvent) flowableEngineEvent);
                // 任务截止日期变更或任务创建事件
                case TASK_DUEDATE_CHANGED, TASK_CREATED -> {
                    // 获取事件中关联的实体对象
                    FlowableEntityEvent flowableEntityEvent = (FlowableEntityEvent) flowableEngineEvent;
                    Object entityObject = flowableEntityEvent.getEntity();
                    TaskEntity task = (TaskEntity) entityObject;
                    // 检查是否需要异步执行器且任务有截止日期
                    if (asyncExecutorActivate && task.getDueDate() != null && task.getDueDate().after(new Date())) {
                        // 获取定时任务服务
                        TimerJobService timerJobService = CommandContextUtil.getTimerJobService();
                        // 查找当前流程实例相关的定时任务
                        List<TimerJobEntity> timerJobEntityList = timerJobService.findTimerJobsByProcessInstanceId(task.getProcessInstanceId());
                        if (!CollUtil.isEmpty(timerJobEntityList)) {
                            // 删除已存在的定时任务
                            for (TimerJobEntity timerJobEntity : timerJobEntityList) {
                                String taskId = timerJobEntity.getJobHandlerConfiguration();
                                if (task.getId().equals(taskId)) {
                                    timerJobService.deleteTimerJob(timerJobEntity);
                                }
                            }
                        }
                        //创建job对象
                        TimerJobEntity timer = timerJobService.createTimerJob();
                        timer.setTenantId(TenantHelper.getTenantId());
                        //设置job类型
                        timer.setJobType(JobEntity.JOB_TYPE_TIMER);
                        timer.setJobHandlerType(TaskTimeoutJobHandler.TYPE);
                        timer.setDuedate(task.getDueDate());
                        timer.setProcessInstanceId(task.getProcessInstanceId());
                        //设置任务id
                        timer.setJobHandlerConfiguration(task.getId());
                        //保存并触发事件
                        timerJobService.scheduleTimerJob(timer);
                    }
                }
            }
        }
    }

    /**
     * 覆写isFailOnException方法
     * 指定在事件处理过程中是否失败异常
     *
     * @return boolean值，此处返回true表示在事件处理过程中会失败异常
     */
    @Override
    public boolean isFailOnException() {
        return true;
    }

    /**
     * 覆写isFireOnTransactionLifecycleEvent方法
     * 指定是否在事务生命周期事件上触发
     *
     * @return boolean值，此处返回false表示不会在事务生命周期事件上触发
     */
    @Override
    public boolean isFireOnTransactionLifecycleEvent() {
        return false;
    }

    /**
     * 覆写getOnTransaction方法
     * 获取事件在事务中的状态
     *
     * @return 返回事务状态的字符串表示，此处返回COMMITTED表示事务已提交
     */
    @Override
    public String getOnTransaction() {
        return TransactionState.COMMITTED.name();
    }

    /**
     * 处理边界定时事件自动审批记录
     * 主要用于处理边界事件的情况，如果任务没有评论，则添加一个超时自动审批的评论
     *
     * @param event 事件，Flowable引擎实体事件，不应为null
     */
    protected void jobExecutionSuccess(FlowableEngineEntityEvent event) {
        // 确保事件和执行ID不为空
        if (event != null && StringUtils.isNotBlank(event.getExecutionId())) {
            // 查询执行对象
            Execution execution = runtimeService.createExecutionQuery().executionId(event.getExecutionId()).singleResult();
            // 确保执行对象不为空
            if (execution != null) {
                // 获取流程模型
                BpmnModel bpmnModel = repositoryService.getBpmnModel(event.getProcessDefinitionId());
                // 获取当前执行的流程元素
                FlowElement flowElement = bpmnModel.getFlowElement(execution.getActivityId());
                // 判断当前流程元素是否为边界事件
                if (flowElement instanceof BoundaryEvent) {
                    // 获取边界事件所附着的元素ID
                    String attachedToRefId = ((BoundaryEvent) flowElement).getAttachedToRefId();
                    // 查询附着元素相关的所有执行对象
                    List<Execution> list = runtimeService.createExecutionQuery().activityId(attachedToRefId).list();
                    // 遍历执行对象列表
                    for (Execution ex : list) {
                        // 查询任务对象
                        Task task = QueryUtils.taskQuery().executionId(ex.getId()).singleResult();
                        // 确保任务对象不为空
                        if (task != null) {
                            // 查询任务的所有评论
                            List<Comment> taskComments = taskService.getTaskComments(task.getId());
                            // 如果任务没有评论
                            if (CollUtil.isEmpty(taskComments)) {
                                // 添加一个超时自动审批的评论
                                taskService.addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.PASS.getStatus(), "超时自动审批!");
                            }
                        }
                    }
                }
            }
        }
    }
}
